home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume25 / zip / part06 < prev    next >
Encoding:
Text File  |  1992-03-01  |  46.4 KB  |  1,708 lines

  1. Newsgroups: comp.sources.unix
  2. From: madler@cco.caltech.edu (Mark Adler)
  3. Subject: v25i147: zip - file compression/archive tool, Part06/07
  4. Sender: unix-sources-moderator@pa.dec.com
  5. Approved: vixie@pa.dec.com
  6.  
  7. Submitted-By: madler@cco.caltech.edu (Mark Adler)
  8. Posting-Number: Volume 25, Issue 147
  9. Archive-Name: zip/part06
  10.  
  11. #! /bin/sh
  12. # This is a shell archive.  Remove anything before this line, then unpack
  13. # it by saving it into a file and typing "sh file".  To overwrite existing
  14. # files, type "sh file -c".  You can also feed this as standard input via
  15. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  16. # will see the following message at the end:
  17. #        "End of archive 6 (of 7)."
  18. # Contents:  fileio.c
  19. # Wrapped by vixie@cognition.pa.dec.com on Sun Mar  1 18:57:39 1992
  20. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  21. if test -f 'fileio.c' -a "${1}" != "-c" ; then 
  22.   echo shar: Will not clobber existing file \"'fileio.c'\"
  23. else
  24. echo shar: Extracting \"'fileio.c'\" \(44358 characters\)
  25. sed "s/^X//" >'fileio.c' <<'END_OF_FILE'
  26. X/*
  27. X
  28. X Copyright (C) 1990,1991 Mark Adler, Richard B. Wales, and Jean-loup Gailly.
  29. X Permission is granted to any individual or institution to use, copy, or
  30. X redistribute this software so long as all of the original files are included
  31. X unmodified, that it is not sold for profit, and that this copyright notice
  32. X is retained.
  33. X
  34. X*/
  35. X
  36. X/*
  37. X *  fileio.c by Mark Adler.
  38. X */
  39. X
  40. X#include "zip.h"
  41. X
  42. X#include <time.h>
  43. X#include <errno.h>
  44. X
  45. X#ifdef S_IWUSR          /* For MINIX */
  46. X#  ifdef S_IWRITE
  47. X#    undef S_IWRITE
  48. X#  endif /* S_IWRITE */
  49. X#  define S_IWRITE S_IWUSR
  50. X#endif /* S_IWUSR */
  51. X
  52. X#ifdef MSDOS
  53. X#  include <io.h>
  54. X#  ifdef __TURBOC__
  55. X#    include <dir.h>
  56. X#  else /* !__TURBOC__ */
  57. X#    include <direct.h>
  58. X#  endif /* ?__TURBOC__ */
  59. X#  define link rename
  60. X#  ifdef OS2
  61. X#    define MATCH shmatch
  62. X#  else /* !OS2 */
  63. X#    define MATCH dosmatch
  64. X#  endif /* ?OS2 */
  65. X#else /* !MSDOS */
  66. X   extern int errno;    /* error number from system functions */
  67. X#  ifdef VMS
  68. X#    define RMDIR
  69. X#    define link rename
  70. X#  endif /* VMS */
  71. X#  define MATCH shmatch
  72. X#endif /* ?MSDOS */
  73. X
  74. X#ifdef UTS
  75. X#  define RMDIR
  76. X#endif /* UTS */
  77. X
  78. X
  79. X/* Extra malloc() space in names for cutpath() */
  80. X#ifdef VMS
  81. X#  define PAD 3         /* may have to change .FOO] to ]FOO.DIR */
  82. X#else /* !VMS */
  83. X#  define PAD 0
  84. X#endif /* ?VMS */
  85. X
  86. X
  87. X/* For now, assume DIRENT implies System V implies TERMIO */
  88. X#ifdef DIRENT
  89. X#  ifndef MINIX
  90. X#    ifndef TERMIO
  91. X#      define TERMIO
  92. X#    endif /* !TERMIO */
  93. X#  endif /* !MINIX */
  94. X#endif /* DIRENT */
  95. X
  96. X
  97. X#ifndef EXPORT
  98. X#  ifdef MSVMS
  99. X#    ifdef MSDOS
  100. X#      include <conio.h>
  101. X#    else /* !MSDOS */
  102. X#      define getch() getc(stderr)
  103. X#    endif /* ?MSDOS */
  104. X#  else /* !MSVMS */
  105. X#    ifdef TERMIO       /* Amdahl, Cray, all SysV? */
  106. X#      ifdef CONVEX
  107. X#        include <sys/termios.h>
  108. X#        include <sgtty.h>
  109. X#      else /* !CONVEX */
  110. X#        include <sys/termio.h>
  111. X#        define sgttyb termio
  112. X#        define sg_flags c_lflag
  113. X#      endif /* ?CONVEX */
  114. X       int ioctl OF((int, int, voidp *));
  115. X#      define GTTY(f,s) ioctl(f,TCGETA,s)
  116. X#      define STTY(f,s) ioctl(f,TCSETAW,s)
  117. X#    else /* !TERMIO */
  118. X#      ifndef MINIX
  119. X#        include <sys/ioctl.h>
  120. X#      endif /* !MINIX */
  121. X#      include <sgtty.h>
  122. X       int gtty OF((int, struct sgttyb *));
  123. X       int stty OF((int, struct sgttyb *));
  124. X#      define GTTY gtty
  125. X#      define STTY stty
  126. X#    endif /* ?TERMIO */
  127. X     int isatty OF((int));
  128. X     char *ttyname OF((int));
  129. X     int open OF((char *, int, ...));
  130. X     int close OF((int));
  131. X     int read OF((int, voidp *, int));
  132. X#  endif /* ?MSVMS */
  133. X#endif /* !EXPORT */
  134. X
  135. X
  136. X
  137. X/* For directory access */
  138. X#ifndef UTIL
  139. X#ifdef DIRENT                   /* use getdents() */
  140. X#  ifdef MINIX
  141. X#    include <dirent.h>
  142. X#  else /* !MINIX */
  143. X#    include <sys/dirent.h>
  144. X#  endif /* ?MINIX */
  145. X#  define direct dirent
  146. X#  ifdef MINIX
  147. X     int getdents OF((int, char *, unsigned));
  148. X#  else /* !MINIX */
  149. X     int getdents OF((int, char *, int));
  150. X#  endif /* ?MINIX */
  151. X#  define DBSZ 4096     /* This has to be bigger than a directory block */
  152. X   typedef struct {     /* directory stream buffer */
  153. X     int f;             /* file descriptor for the directory "file" */
  154. X     char *p;           /* pointer to next entry in buffer */
  155. X     char *q;           /* pointer after end of buffer contents */
  156. X     char b[DBSZ];              /* buffer */
  157. X   } dstrm;
  158. X#else /* !DIRENT */             /* use opendir(), etc. */
  159. X#  ifdef CONVEX
  160. X#    include <dirent.h>
  161. X#    define direct dirent
  162. X#  endif /* CONVEX */
  163. X#  ifdef NDIR
  164. X#    include "ndir.h"           /* for HPUX */
  165. X#  else /* !NDIR */
  166. X#    ifdef MSDOS
  167. X#     ifdef OS2
  168. X#      include "dir_os2.h"
  169. X#     else /* !OS2 */
  170. X#      include <dos.h>
  171. X#      ifdef __TURBOC__
  172. X#        define FATTR           FA_HIDDEN+FA_SYSTEM+FA_DIREC
  173. X#        define FFIRST(n,d)     findfirst(n,(struct ffblk *)d,FATTR)
  174. X#        define FNEXT(d)        findnext((struct ffblk *)d)
  175. X#      else /* !__TURBOC__ */
  176. X#        define FATTR           _A_HIDDEN+_A_SYSTEM+_A_SUBDIR
  177. X#        define FFIRST(n,d)     _dos_findfirst(n,FATTR,(struct find_t *)d)
  178. X#        define FNEXT(d)        _dos_findnext((struct find_t *)d)
  179. X#      endif /* ?__TURBOC__ */
  180. X       typedef struct direct {
  181. X         char d_reserved[30];
  182. X         char d_name[13];
  183. X         int d_first;
  184. X       } DIR;
  185. X#     endif /* ?OS2 */
  186. X#    else /* !MSDOS */
  187. X#      ifdef VMS
  188. X#        include <rms.h>
  189. X#        include <ssdef.h>
  190. X#        include <descrip.h>
  191. X         typedef struct direct {
  192. X             int d_wild;                /* flag for wildcard vs. non-wild */
  193. X             struct FAB fab;
  194. X             struct NAM nam;
  195. X             char d_qualwildname[NAM$C_MAXRSS + 1];
  196. X             char d_name[NAM$C_MAXRSS + 1];
  197. X         } DIR;
  198. X#      else /* !VMS */
  199. X#        include <sys/dir.h>
  200. X#        ifdef NODIR                    /* for AT&T 3B1 */
  201. X#          define dirent direct
  202. X           typedef FILE DIR;
  203. X#          define dstrm DIR
  204. X#        endif /* NODIR */
  205. X#      endif /* ?VMS */
  206. X#    endif /* ?MSDOS */
  207. X#  endif /* ?NDIR */
  208. X#  define dstrm DIR
  209. X#  ifndef NODIR
  210. X     DIR *opendir OF((char *));
  211. X#  endif /* !NODIR */
  212. X#  ifndef CONVEX
  213. X     struct direct *readdir OF((DIR *));
  214. X#  endif /* !CONVEX */
  215. X#endif /* ?DIRENT */
  216. X#endif /* !UTIL */
  217. X
  218. X
  219. X/* Library functions not in (most) header files */
  220. char *mktemp OF((char *));
  221. int link OF((char *, char *));
  222. int unlink OF((char *));
  223. X#ifndef CONVEX
  224. X#  ifndef AIX
  225. X     int chmod OF((char *, int));
  226. X#  endif /* !AIX */
  227. X#endif /* !CONVEX */
  228. X
  229. X
  230. X#ifndef UTIL    /* the companion #endif is a bit of ways down ... */
  231. X
  232. X#ifndef __TURBOC__
  233. X   int utime OF((char *, time_t *));
  234. X#endif /* !__TURBOC__ */
  235. X#ifndef MSDOS
  236. X   int open OF((char *, int, ...));
  237. X   int close OF((int));
  238. X#  ifndef RMDIR
  239. X     int rmdir OF((char *));
  240. X#  endif /* !RMDIR */
  241. X#endif /* !MSDOS */
  242. X
  243. X
  244. X/* Local globals (kinda like "military intelligence" or "broadcast quality") */
  245. local int exflag = 0;           /* Exclude flag */
  246. X
  247. X/* Local functions */
  248. X#ifdef PROTO
  249. X#  ifdef VMS
  250. X     local void vms_wild(char *, dstrm *);
  251. X#  endif /* VMS */
  252. X#  ifdef DIRENT
  253. X     local dstrm *opend(char *);
  254. X     local void closed(dstrm *);
  255. X#  endif /* DIRENT */
  256. X   local char *readd(dstrm *);
  257. X   local int fqcmp(voidp *, voidp *);
  258. X   local int fqcmpz(voidp *, voidp *);
  259. X   local char *last(char *);
  260. X   local char *msname(char *);
  261. X#  ifdef VMS
  262. X     local char *strlower(char *);
  263. X     local char *strupper(char *);
  264. X#  endif /* VMS */
  265. X   local char *ex2in(char *);
  266. X   local int newname(char *);
  267. X   local void inctime(struct tm *);
  268. X   local ulg unix2dostime(time_t *);
  269. X#  ifndef __TURBOC__
  270. X     local int cmptime(struct tm *, struct tm *);
  271. X     local time_t invlocal(struct tm *);
  272. X#  endif /* !__TURBOC__ */
  273. X#endif /* PROTO */
  274. X
  275. X
  276. X
  277. X#ifndef OS2
  278. X#ifdef MSDOS
  279. dstrm *opendir(n)
  280. char *n;                /* directory to open */
  281. X/* Start searching for files in the MSDOS directory n */
  282. X{
  283. X  dstrm *d;             /* malloc'd return value */
  284. X  char *p;              /* malloc'd temporary string */
  285. X
  286. X  if ((d = (dstrm *)malloc(sizeof(dstrm))) == NULL ||
  287. X      (p = malloc(strlen(n) + 5)) == NULL)
  288. X    return NULL;
  289. X  strcat(strcpy(p, n), "/*.*");
  290. X  if (FFIRST(p, d))
  291. X  {
  292. X    free((voidp *)p);
  293. X    return NULL;
  294. X  }
  295. X  free((voidp *)p);
  296. X  d->d_first = 1;
  297. X  return d;
  298. X}
  299. X
  300. struct direct *readdir(d)
  301. dstrm *d;               /* directory stream to read from */
  302. X/* Return pointer to first or next directory entry, or NULL if end. */
  303. X{
  304. X  if (d->d_first)
  305. X    d->d_first = 0;
  306. X  else
  307. X    if (FNEXT(d))
  308. X      return NULL;
  309. X  return (struct direct *)d;
  310. X}
  311. X#  define closedir free
  312. X#endif /* MSDOS */
  313. X#endif /* !OS2 */
  314. X
  315. X
  316. X#ifdef VMS
  317. X/*---------------------------------------------------------------------------
  318. X
  319. X    _vms_findfirst() and _vms_findnext(), based on public-domain DECUS C
  320. X    fwild() and fnext() routines (originally written by Martin Minow, poss-
  321. X    ibly modified by Jerry Leichter for bintnxvms.c), were written by Greg
  322. X    Roelofs and are still in the public domain.  Routines approximate the
  323. X    behavior of MS-DOS (MSC and Turbo C) findfirst and findnext functions.
  324. X
  325. X  ---------------------------------------------------------------------------*/
  326. local void vms_wild(p, d)
  327. char *p;
  328. dstrm *d;
  329. X{
  330. X  /*
  331. X   * Do wildcard setup
  332. X   */
  333. X  /* set up the FAB and NAM blocks. */
  334. X  d->fab = cc$rms_fab;             /* initialize fab */
  335. X  d->nam = cc$rms_nam;             /* initialize nam */
  336. X
  337. X  d->fab.fab$l_nam = &d->nam;           /* fab -> nam */
  338. X  d->fab.fab$l_fna = p;                 /* argument wild name */
  339. X  d->fab.fab$b_fns = strlen(p);         /* length */
  340. X
  341. X  d->nam.nam$l_esa = d->d_qualwildname; /* qualified wild name */
  342. X  d->nam.nam$b_ess = NAM$C_MAXRSS;      /* max length */
  343. X  d->nam.nam$l_rsa = d->d_name;         /* matching file name */
  344. X  d->nam.nam$b_rss = NAM$C_MAXRSS;      /* max length */
  345. X
  346. X  /* parse the file name */
  347. X  if (sys$parse(&d->fab) != RMS$_NORMAL)
  348. X    return -1;
  349. X  /* Does this replace d->fab.fab$l_fna with a new string in its own space?
  350. X     I sure hope so, since p is free'ed before this routine returns. */
  351. X
  352. X  /* have qualified wild name (i.e., disk:[dir.subdir]*.*); null-terminate
  353. X   * and set wild-flag */
  354. X  d->d_qualwildname[d->nam.nam$b_esl] = '\0';
  355. X  d->d_wild = (d->nam.nam$l_fnb & NAM$M_WILDCARD)? 1 : 0;   /* not used... */
  356. X#ifdef DEBUG
  357. X  printf("  incoming wildname:  %s\n", p);
  358. X  printf("  qualified wildname:  %s\n", d->d_qualwildname);
  359. X#endif /* DEBUG */
  360. X}
  361. X
  362. dstrm *opendir(n)
  363. char *n;                /* directory to open */
  364. X/* Start searching for files in the VMS directory n */
  365. X{
  366. X  char *c;              /* scans VMS path */
  367. X  dstrm *d;             /* malloc'd return value */
  368. X  int m;                /* length of name */
  369. X  char *p;              /* malloc'd temporary string */
  370. X
  371. X  if ((d = (dstrm *)malloc(sizeof(dstrm))) == NULL ||
  372. X      (p = malloc((m = strlen(n)) + 4)) == NULL)
  373. X    return NULL;
  374. X  /* Directory may be in form "[DIR.SUB1.SUB2]" or "[DIR.SUB1]SUB2.DIR;1".
  375. X     If latter, convert to former. */
  376. X  if (m > 0  &&  *(c = strcpy(p,n)+m-1) != ']')
  377. X  {
  378. X    while (--c > p  &&  *c != ';')
  379. X      ;
  380. X    if (c-p < 5  ||  strncmp(c-4, ".DIR", 4))
  381. X    {
  382. X      free((voidp *)d);  free((voidp *)p);
  383. X      return NULL;
  384. X    }
  385. X    c -= 3;
  386. X    *c-- = '\0';        /* terminate at "DIR;#" */
  387. X    *c = ']';           /* "." --> "]" */
  388. X    while (c > p  &&  *--c != ']')
  389. X      ;
  390. X    *c = '.';           /* "]" --> "." */
  391. X  }
  392. X  strcat(p, "*.*");
  393. X  vms_wild(p, d);       /* set up wildcard */
  394. X  free((voidp *)p);
  395. X  return d;
  396. X}
  397. X
  398. struct direct *readdir(d)
  399. dstrm *d;               /* directory stream to read from */
  400. X/* Return pointer to first or next directory entry, or NULL if end. */
  401. X{
  402. X  int r;                /* return code */
  403. X
  404. X  do {
  405. X    d->fab.fab$w_ifi = 0;       /* internal file index:  what does this do? */
  406. X
  407. X    /* get next match to possible wildcard */
  408. X    if ((r = sys$search(&d->fab)) == RMS$_NORMAL)
  409. X    {
  410. X        d->d_name[d->nam.nam$b_rsl] = '\0';   /* null terminate */
  411. X        return (struct direct *)d;   /* OK */
  412. X    }
  413. X  } while (r == RMS$_PRV);
  414. X  return NULL;
  415. X}
  416. X#  define closedir free
  417. X#endif /* VMS */
  418. X
  419. X
  420. X#ifdef NODIR                    /* for AT&T 3B1 */
  421. X/*
  422. X**  Apparently originally by Rich Salz.
  423. X**  Cleaned up and modified by James W. Birdsall.
  424. X*/
  425. X
  426. X#  define opendir(path) fopen(path, "r")
  427. struct direct *readdir(dirp)
  428. DIR *dirp;
  429. X{
  430. X  static struct direct entry;
  431. X
  432. X  if (dirp == NULL) 
  433. X    return NULL;
  434. X  for (;;)
  435. X    if (fread (&entry, sizeof (struct direct), 1, dirp) == 0) 
  436. X      return NULL;
  437. X    else if (entry.d_ino) 
  438. X      return (&entry);
  439. X} /* end of readdir() */
  440. X
  441. X#  define closedir(dirp) fclose(dirp)
  442. X#endif /* NODIR */
  443. X
  444. X
  445. X#ifdef DIRENT
  446. local dstrm *opend(n)
  447. char *n;                /* directory name to open */
  448. X/* Open the directory *n, returning a pointer to an allocated dstrm, or
  449. X   NULL if error. */
  450. X{
  451. X  dstrm *d;             /* pointer to malloc'ed directory stream */
  452. X
  453. X  if ((d = (dstrm *)malloc(sizeof(dstrm))) == NULL)
  454. X    return NULL;
  455. X  if ((d->f = open(n, 0, 0)) < 0)               /* open directory */
  456. X    return NULL;
  457. X  d->p = d->q = d->b;                           /* buffer is empty */
  458. X  return d;
  459. X}
  460. X#else /* !DIRENT */
  461. X#  define opend opendir                         /* just use opendir() */
  462. X#endif /* ?DIRENT */
  463. X
  464. X
  465. local char *readd(d)
  466. dstrm *d;               /* directory stream to read from */
  467. X/* Return a pointer to the next name in the directory stream d, or NULL if
  468. X   no more entries or an error occurs. */
  469. X{
  470. X  struct direct *e;     /* directory entry read */
  471. X
  472. X#ifdef DIRENT
  473. X  int n;                /* number of entries read by getdents */
  474. X
  475. X  if (d->p >= d->q)                             /* if empty, fill buffer */
  476. X    if ((n = getdents(d->f, d->b, DBSZ)) <= 0)
  477. X      return NULL;
  478. X    else
  479. X      d->q = n + (d->p = d->b);
  480. X  e = (struct direct *)(d->p);                  /* point to entry */
  481. X  d->p += ((struct direct *)(d->p))->d_reclen;  /* advance */
  482. X  return e->d_name;                             /* return name */
  483. X#else /* !DIRENT */
  484. X  return (e = readdir(d)) == NULL ? (char *)NULL : e->d_name;
  485. X#endif /* ?DIRENT */
  486. X}
  487. X
  488. X
  489. X#ifdef DIRENT
  490. local void closed(d)
  491. dstrm *d;               /* directory stream to close */
  492. X/* Close the directory stream */
  493. X{
  494. X  close(d->f);
  495. X  free((voidp *)d);
  496. X}
  497. X#else /* !DIRENT */
  498. X#  define closed closedir
  499. X#endif /* ?DIRENT */
  500. X
  501. X
  502. X#ifdef MSDOS
  503. int wild(p)
  504. char *p;                /* path/pattern to match */
  505. X/* If not in exclude mode, expand the pattern based on the contents of the
  506. X   file system.  Return an error code in the ZE_ class. */
  507. X{
  508. X  dstrm *d;             /* stream for reading directory */
  509. X  char *e;              /* name found in directory */
  510. X  int f;                /* true if there was a match */
  511. X  char *n;              /* constructed name from directory */
  512. X  char *q;              /* temporary variable */
  513. X  int r;                /* temporary variable */
  514. X  char v[4];            /* space for device current directory */
  515. X
  516. X  /* If excluding, don't bother with file system */
  517. X  if (exflag)
  518. X    return procname(p);
  519. X
  520. X  /* Normalize pattern to upper case, path delimiter as '/'. */
  521. X#ifndef OS2
  522. X  strupr(p);                            /* convert to upper case */
  523. X#endif /* !OS2 */
  524. X  for (q = p; *q; q++)                  /* use / consistently */
  525. X    if (*q == '\\')
  526. X      *q = '/';
  527. X
  528. X  /* Only name can have special matching characters */
  529. X  if ((q = isshexp(p)) != NULL &&
  530. X      (strrchr(q, '/') != NULL || strrchr(q, ':') != NULL))
  531. X    return ZE_PARMS;
  532. X
  533. X  /* Separate path and name */
  534. X  if ((q = strrchr(p, '/')) != NULL)
  535. X    *q++ = 0;
  536. X  else if (*p && *(p+1) == ':')
  537. X  {
  538. X    q = p + 2;
  539. X    v[0] = *p;
  540. X    strcpy(v+1, ":.");
  541. X    p = v;
  542. X  }
  543. X  else
  544. X  {
  545. X    q = p;
  546. X    p = ".";
  547. X  }
  548. X  if (*p == 0)
  549. X    p = "/";
  550. X
  551. X  /* Search that level for matching names */
  552. X  if ((d = opend(p)) == NULL)
  553. X    return ZE_MISS;
  554. X  if (strcmp(p+1, ":.") == 0)
  555. X    *(p+2) = 0;
  556. X  f = 0;
  557. X  while ((e = readd(d)) != NULL)
  558. X    if (strcmp(e, ".") && strcmp(e, "..") && MATCH(q, e))
  559. X    {
  560. X      f = 1;
  561. X      if (strcmp(p, ".") == 0)
  562. X        procname(e);
  563. X      else if (*p && strcmp(p+1, ":") == 0)
  564. X      {
  565. X        if ((n = malloc(strlen(e) + 3)) == NULL)
  566. X          return ZE_MEM;
  567. X        r = procname(strcat(strcpy(n, p), e));
  568. X        free((voidp *)n);
  569. X        if (r)
  570. X          return r;
  571. X      }
  572. X      else
  573. X      {
  574. X        if ((n = malloc(strlen(p) + strlen(e) + 2)) == NULL)
  575. X          return ZE_MEM;
  576. X        if (strcmp(p, "/"))
  577. X          strcpy(n, p);
  578. X        else
  579. X          *n = 0;
  580. X        r = procname(strcat(strcat(n, "/"), e));
  581. X        free((voidp *)n);
  582. X        if (r)
  583. X          return r;
  584. X      }
  585. X    }
  586. X  closed(d);
  587. X
  588. X  /* Done */
  589. X  return f ? ZE_OK : ZE_MISS;
  590. X}
  591. X#endif /* MSDOS */
  592. X
  593. X
  594. X#ifdef VMS
  595. int wild(p)
  596. char *p;                /* path/pattern to match */
  597. X/* Expand the pattern based on the contents of the file system.  Return an
  598. X   error code in the ZE_ class. */
  599. X{
  600. X  dstrm *d;             /* stream for reading directory */
  601. X  char *e;              /* name found in directory */
  602. X  int f;                /* true if there was a match */
  603. X
  604. X  /* Search given pattern for matching names */
  605. X  if ((d = (dstrm *)malloc(sizeof(dstrm))) == NULL)
  606. X    return ZE_MEM;
  607. X  vms_wild(p, d);       /* pattern may be more than just directory name */
  608. X  f = 0;
  609. X  while ((e = readd(d)) != NULL)        /* "dosmatch" is already built in */
  610. X    if (procname(e) == ZE_OK)
  611. X      f = 1;
  612. X  closed(d);
  613. X
  614. X  /* Done */
  615. X  return f ? ZE_OK : ZE_MISS;
  616. X}
  617. X#endif /* VMS */
  618. X
  619. X
  620. char *getnam(n)
  621. char *n;                /* where to put name (must have >=FNMAX+1 bytes) */
  622. X/* Read a space, \n, \r, or \t delimited name from stdin into n, and return
  623. X   n.  If EOF, then return NULL.  Also, if the name read is too big, return
  624. X   NULL. */
  625. X{
  626. X  int c;                /* last character read */
  627. X  char *p;              /* pointer into name area */
  628. X
  629. X  p = n;
  630. X  while ((c = getchar()) == ' ' || c == '\n' || c == '\r' || c == '\t')
  631. X    ;
  632. X  if (c == EOF)
  633. X    return NULL;
  634. X  do {
  635. X    if (p - n >= FNMAX)
  636. X      return NULL;
  637. X    *p++ = (char)c;
  638. X    c = getchar();
  639. X  } while (c != EOF && c != ' ' && c != '\n' && c != '\r' && c != '\t');
  640. X  *p = 0;
  641. X  return n;
  642. X}
  643. X
  644. X
  645. struct flist far *fexpel(f)
  646. struct flist far *f;    /* entry to delete */
  647. X/* Delete the entry *f in the doubly-linked found list.  Return pointer to
  648. X   next entry to allow stepping through list. */
  649. X{
  650. X  struct flist far *t;  /* temporary variable */
  651. X
  652. X  t = f->nxt;
  653. X  *(f->lst) = t;                        /* point last to next, */
  654. X  if (t != NULL)
  655. X    t->lst = f->lst;                    /* and next to last */
  656. X  if (f->name != NULL)                  /* free memory used */
  657. X    free((voidp *)(f->name));
  658. X  if (f->zname != NULL)
  659. X    free((voidp *)(f->zname));
  660. X  farfree((voidp far *)f);
  661. X  fcount--;                             /* decrement count */
  662. X  return t;                             /* return pointer to next */
  663. X}
  664. X
  665. X
  666. local int fqcmp(a, b)
  667. voidp *a, *b;           /* pointers to pointers to found entries */
  668. X/* Used by qsort() to compare entries in the found list by name. */
  669. X{
  670. X  return strcmp((*(struct flist far **)a)->name,
  671. X                (*(struct flist far **)b)->name);
  672. X}
  673. X
  674. X
  675. local int fqcmpz(a, b)
  676. voidp *a, *b;           /* pointers to pointers to found entries */
  677. X/* Used by qsort() to compare entries in the found list by zname. */
  678. X{
  679. X  return strcmp((*(struct flist far **)a)->zname,
  680. X                (*(struct flist far **)b)->zname);
  681. X}
  682. X
  683. X
  684. local char *last(p)
  685. char *p;                /* sequence of / delimited path components */
  686. X/* Return a pointer to the start of the last path component. */
  687. X{
  688. X  char *t;              /* temporary variable */
  689. X
  690. X#ifdef VMS
  691. X  if ((t = strrchr(p, ']')) != NULL)
  692. X#else /* !VMS */
  693. X  if ((t = strrchr(p, '/')) != NULL)
  694. X#endif /* ?VMS */
  695. X    return t + 1;
  696. X  else
  697. X    return p;
  698. X}
  699. X
  700. X
  701. X#define TOUP(c) ((c) >= 'a' && (c) <= 'z' ? (c)-'a'+'A' : (c))
  702. X
  703. local char *msname(n)
  704. char *n;
  705. X/* Reduce all path components to MSDOS upper case 8.3 style names.  Probably
  706. X   should also check for invalid characters, but I don't know which ones
  707. X   those are. */
  708. X{
  709. X  int c;                /* current character */
  710. X  int f;                /* characters in current component */
  711. X  char *p;              /* source pointer */
  712. X  char *q;              /* destination pointer */
  713. X
  714. X  p = q = n;
  715. X  f = 0;
  716. X  while ((c = *p++) != 0)
  717. X    if (c == '/')
  718. X    {
  719. X      *q++ = (char)c;
  720. X      f = 0;                            /* new component */
  721. X    }
  722. X    else if (c == '.')
  723. X      if (f < 9)
  724. X      {
  725. X        *q++ = (char)c;
  726. X        f = 9;                          /* now in file type */
  727. X      }
  728. X      else
  729. X        f = 12;                         /* now just excess characters */
  730. X    else
  731. X      if (f < 12 && f != 8)
  732. X      {
  733. X        *q++ = (char)(TOUP(c));
  734. X        f++;                            /* do until end of name or type */
  735. X      }
  736. X  *q = 0;
  737. X  return n;
  738. X}
  739. X
  740. X
  741. X#ifdef VMS
  742. local char *strlower(s)
  743. char *s;                /* string to convert */
  744. X/* Convert all uppercase letters to lowercase in string s */
  745. X{
  746. X  char *p;              /* scans string */
  747. X
  748. X  for (p = s; *p; p++)
  749. X    if (*p >= 'A' && *p <= 'Z')
  750. X      *p += 'a' - 'A';
  751. X  return s;
  752. X}
  753. X
  754. local char *strupper(s)
  755. char *s;                /* string to convert */
  756. X/* Convert all lowercase letters to uppercase in string s */
  757. X{
  758. X  char *p;              /* scans string */
  759. X
  760. X  for (p = s; *p; p++)
  761. X    if (*p >= 'a' && *p <= 'a')
  762. X      *p -= 'a' - 'A';
  763. X  return s;
  764. X}
  765. X#endif /* VMS */
  766. X
  767. X
  768. local char *ex2in(x)
  769. char *x;                /* external file name */
  770. X/* Convert the external file name to a zip file name, returning the malloc'ed
  771. X   string or NULL if not enough memory. */
  772. X{
  773. X  char *n;              /* internal file name (malloc'ed) */
  774. X  char *t;              /* shortened name */
  775. X
  776. X  /* Find starting point in name before doing malloc */
  777. X#ifdef MSDOS                            /* msdos */
  778. X  t = *x && *(x + 1) == ':' ? x + 2 : x;
  779. X  while (*t == '/' || *t == '\\')
  780. X    t++;
  781. X#else /* !MSDOS */
  782. X#  ifdef VMS                            /* vms */
  783. X  t = x;
  784. X  if ((n = strrchr(t, ':')) != NULL)
  785. X    t = n + 1;
  786. X  if (*t == '[' && (n = strrchr(t, ']')) != NULL)
  787. X    if ((x = strchr(t, '.')) != NULL && x < n)
  788. X      t = x + 1;
  789. X    else
  790. X      t = n + 1;
  791. X#  else /* !VMS */                      /* unix */
  792. X  for (t = x; *t == '/'; t++)
  793. X    ;
  794. X#  endif /* ?VMS */
  795. X#endif /* ?MSDOS */
  796. X  if (!pathput)
  797. X    t = last(t);
  798. X
  799. X  /* Malloc space for internal name and copy it */
  800. X  if ((n = malloc(strlen(t) + 1)) == NULL)
  801. X    return NULL;
  802. X  strcpy(n, t);
  803. X
  804. X  /* Make changes, if any, to the copied name (leave original intact) */
  805. X#ifdef MSDOS
  806. X  for (t = n; *t; t++)
  807. X    if (*t == '\\')
  808. X      *t = '/';
  809. X#endif /* MSDOS */
  810. X#ifdef VMS
  811. X  if ((t = strrchr(n, ']')) != NULL)
  812. X  {
  813. X    *t = '/';
  814. X    while (--t > n)
  815. X      if (*t == '.')
  816. X        *t = '/';
  817. X  }
  818. X
  819. X  /* Fix from Greg Roelofs: */
  820. X  /* Get current working directory and strip from n (t now = n) */
  821. X  {
  822. X    char cwd[256], *p, *q;
  823. X    int c;
  824. X
  825. X    if (getcwd(cwd, 256) && ((p = strchr(cwd, '.')) != NULL))
  826. X    {
  827. X      ++p;
  828. X      if ((q = strrchr(p, ']')) != NULL)
  829. X      {
  830. X        *q = '/';
  831. X        while (--q > p)
  832. X          if (*q == '.')
  833. X            *q = '/';
  834. X        /* strip bogus path parts from n */
  835. X        if (strncmp(n, p, (c=strlen(p))) == 0)
  836. X        {
  837. X          q = n + c;
  838. X          while (*t++ = *q++)
  839. X            ;
  840. X        }
  841. X      }
  842. X    }
  843. X  }
  844. X  strlower(n);
  845. X  if (!vmsver)
  846. X    if ((t = strrchr(n, ';')) != NULL)
  847. X      *t = 0;
  848. X#endif /* VMS */
  849. X  if (dosify)
  850. X    msname(n);
  851. X
  852. X  /* Returned malloc'ed name */
  853. X  return n;
  854. X}
  855. X
  856. X
  857. char *in2ex(n)
  858. char *n;                /* internal file name */
  859. X/* Convert the zip file name to an external file name, returning the malloc'ed
  860. X   string or NULL if not enough memory. */
  861. X{
  862. X  char *x;              /* external file name */
  863. X#ifdef VMS
  864. X  char *t;              /* scans name */
  865. X
  866. X  if ((t = strrchr(n, '/')) == NULL)
  867. X#endif /* VMS */
  868. X  {
  869. X    if ((x = malloc(strlen(n) + 1 + PAD)) == NULL)
  870. X      return NULL;
  871. X    strcpy(x, n);
  872. X  }
  873. X#ifdef VMS
  874. X  else
  875. X  {
  876. X    if ((x = malloc(strlen(n) + 3 + PAD)) == NULL)
  877. X      return NULL;
  878. X    strcpy(x, "[.");
  879. X    strcpy(x + 2, n);
  880. X    *(t = x + 2 + (t - n)) = ']';
  881. X    while (--t > x)
  882. X      if (*t == '/')
  883. X        *t = '.';
  884. X  }
  885. X  strupper(x);
  886. X#endif /* VMS */
  887. X  return x;
  888. X}
  889. X
  890. X
  891. int exclude()
  892. X/* Change from including to excluding names when procname() called.  Return
  893. X   an error code in the ZE_ class. */
  894. X{
  895. X  struct flist far *f;          /* steps through found linked list */
  896. X  int j;                        /* index for s */
  897. X  struct flist far **s;         /* sorted table */
  898. X
  899. X  /* sort found list, remove duplicates */
  900. X  if (fcount)
  901. X  {
  902. X    if ((s = (struct flist far **)malloc(
  903. X         fcount * sizeof(struct flist far *))) == NULL)
  904. X      return ZE_MEM;
  905. X    for (j = 0, f = found; f != NULL; f = f->nxt)
  906. X      s[j++] = f;
  907. X    qsort((char *)s, fcount, sizeof(struct flist far *), fqcmp);
  908. X    for (j = fcount - 1; j > 0; j--)
  909. X      if (strcmp(s[j - 1]->name, s[j]->name) == 0)
  910. X        fexpel(s[j]);           /* fexpel() changes fcount */
  911. X    qsort((char *)s, fcount, sizeof(struct flist far *), fqcmpz);
  912. X    for (j = 1; j < fcount; j++)
  913. X      if (strcmp(s[j - 1]->zname, s[j]->zname) == 0)
  914. X      {
  915. X        warn("name in zip file repeated: ", s[j]->zname);
  916. X        warn("  first full name: ", s[j - 1]->name);
  917. X        warn(" second full name: ", s[j]->name);
  918. X        return ZE_PARMS;
  919. X      }
  920. X    free((voidp *)s);
  921. X  }
  922. X  exflag = 1;
  923. X  return ZE_OK;
  924. X}
  925. X
  926. X
  927. local int newname(n)
  928. char *n;                /* name to add (or exclude) */
  929. X/* Add (or exclude) a name that is not in the zip file.  Return an error
  930. X   code in the ZE_ class. */
  931. X{
  932. X  char *m;
  933. X  struct flist far *f;  /* where in found, or new found entry */
  934. X  struct zlist far *z;  /* where in zfiles (if found) */
  935. X
  936. X  /* Search for name in zip file.  If there, mark it, else add to
  937. X     list of new names to do (or remove from that list). */
  938. X  if ((m = ex2in(n)) == NULL)
  939. X    return ZE_MEM;
  940. X  if ((z = zsearch(m)) != NULL)
  941. X    if (exflag)
  942. X    {
  943. X      z->mark = 0;
  944. X      free((voidp *)m);
  945. X      if (verbose)
  946. X        printf("zip diagnostic: excluding %s\n", z->name);
  947. X    }
  948. X    else
  949. X    {
  950. X      free((voidp *)(z->name));
  951. X      free((voidp *)(z->zname));
  952. X      if ((z->name = malloc(strlen(n) + 1 + PAD)) == NULL)
  953. X        return ZE_MEM;
  954. X      strcpy(z->name, n);
  955. X      z->zname = m;
  956. X      z->mark = 1;
  957. X      if (verbose)
  958. X        printf("zip diagnostic: including %s\n", z->name);
  959. X    }
  960. X  else
  961. X    if (exflag)
  962. X    {
  963. X      /* search list for name--if there, remove it */
  964. X      for (f = found; f != NULL; f = f->nxt)
  965. X        if (strcmp(n, f->name) == 0)
  966. X        {
  967. X          fexpel(f);
  968. X          break;
  969. X        }
  970. X      free((voidp *)m);
  971. X    }
  972. X    else
  973. X    {
  974. X      /* allocate space and add to list */
  975. X      if ((f = (struct flist far *)farmalloc(sizeof(struct flist))) == NULL ||
  976. X          (f->name = malloc(strlen(n) + 1 + PAD)) == NULL)
  977. X      {
  978. X        if (f != NULL)
  979. X          farfree((voidp far *)f);
  980. X        return ZE_MEM;
  981. X      }
  982. X      strcpy(f->name, n);
  983. X      f->zname = m;
  984. X      *fnxt = f;
  985. X      f->lst = fnxt;
  986. X      f->nxt = NULL;
  987. X      fnxt = &f->nxt;
  988. X      fcount++;
  989. X    }
  990. X  return ZE_OK;
  991. X}
  992. X
  993. X
  994. int procname(n)
  995. char *n;                /* name to process */
  996. X/* Process a name or sh expression to operate on (or exclude).  Return
  997. X   an error code in the ZE_ class. */
  998. X{
  999. X  char *a;              /* path and name for recursion */
  1000. X  dstrm *d;             /* directory stream from opend() */
  1001. X  char *e;              /* pointer to name from readd() */
  1002. X  struct flist far *f;  /* steps through found list */
  1003. X  int m;                /* matched flag */
  1004. X  char *p;              /* path for recursion */
  1005. X  struct stat s;        /* result of stat() */
  1006. X  struct zlist far *z;  /* steps through zfiles list */
  1007. X
  1008. X  if (
  1009. X#ifdef S_IFLNK          /* if symbolic links exist ... */
  1010. X      linkput ? lstat(n, &s) :
  1011. X#endif /* S_IFLNK */
  1012. X      stat(n, &s)
  1013. X#ifdef __TURBOC__       /* Borland bug: stat() succeeds on wild card names! */
  1014. X      || isshexp(n)
  1015. X#endif /* __TURBOC__ */
  1016. X     )
  1017. X  {
  1018. X    /* Not a file--search for shell expression in zip file */
  1019. X    p = ex2in(n);               /* shouldn't affect matching chars */
  1020. X    m = 1;
  1021. X    for (z = zfiles; z != NULL; z = z->nxt)
  1022. X      if (MATCH(p, z->zname))
  1023. X      {
  1024. X        z->mark = !exflag;
  1025. X        if (verbose)
  1026. X          printf("zip diagnostic: %scluding %s\n",
  1027. X                 exflag ? "ex" : "in", z->name);
  1028. X        m = 0;
  1029. X      }
  1030. X    /* If excluding, also search for expression in found list */
  1031. X    if (exflag)
  1032. X    {
  1033. X      for (f = found; f != NULL;)
  1034. X        if (MATCH(p, f->zname))
  1035. X        {
  1036. X          f = fexpel(f);
  1037. X          m = 0;
  1038. X        }
  1039. X        else
  1040. X          f = f->nxt;
  1041. X    }
  1042. X    free((voidp *)p);
  1043. X    if (m)
  1044. X      return ZE_MISS;           /* no match */
  1045. X  }
  1046. X  else
  1047. X  {
  1048. X    /* Live name--use if file, recurse if directory */
  1049. X#ifdef MSDOS
  1050. X#ifndef OS2
  1051. X    strupr(n);                  /* convert to upper case */
  1052. X#endif /* !OS2 */
  1053. X    for (p = n; *p; p++)        /* use / consistently */
  1054. X      if (*p == '\\')
  1055. X        *p = '/';
  1056. X#endif /* MSDOS */
  1057. X    switch (s.st_mode & S_IFMT)
  1058. X    {
  1059. X      case S_IFREG:             /* add or remove name of file */
  1060. X#ifdef S_IFLNK
  1061. X      case S_IFLNK:
  1062. X#endif /* S_IFLNK */
  1063. X        if ((m = newname(n)) != ZE_OK)
  1064. X          return m;
  1065. X        break;
  1066. X      case S_IFDIR:             /* recurse into directory */
  1067. X        if (recurse && (d = opend(n)) != NULL)
  1068. X        {
  1069. X#ifdef VMS
  1070. X          while ((e = readd(d)) != NULL)
  1071. X            if ((m = procname(e)) != ZE_OK)     /* recurse on name */
  1072. X            {
  1073. X              /* want to just set warning error and continue */
  1074. X              closed(d);
  1075. X              return m;
  1076. X            }
  1077. X#else /* !VMS */
  1078. X          if ((p = malloc(strlen(n)+2)) == NULL)
  1079. X            return ZE_MEM;
  1080. X          if (strcmp(n, ".") == 0)
  1081. X            *p = 0;                     /* avoid "./" prefix */
  1082. X          else
  1083. X          {
  1084. X            strcpy(p, n);
  1085. X            a = p + strlen(p);
  1086. X            if (a[-1] != '/')
  1087. X              strcpy(a, "/");
  1088. X          }
  1089. X          while ((e = readd(d)) != NULL)
  1090. X            if (strcmp(e, ".") && strcmp(e, ".."))
  1091. X            {
  1092. X              if ((a = malloc(strlen(p) + strlen(e) + 1)) == NULL)
  1093. X              {
  1094. X                free((voidp *)p);
  1095. X                closed(d);
  1096. X                return ZE_MEM;
  1097. X              }
  1098. X              strcat(strcpy(a, p), e);
  1099. X              if ((m = procname(a)) != ZE_OK)   /* recurse on name */
  1100. X              {
  1101. X                free((voidp *)a);  free((voidp *)p);
  1102. X                closed(d);
  1103. X                return m;
  1104. X              }
  1105. X              free((voidp *)a);
  1106. X            }
  1107. X          free((voidp *)p);
  1108. X#endif /* ?VMS */
  1109. X          closed(d);
  1110. X        }
  1111. X      }
  1112. X    }
  1113. X  return ZE_OK;
  1114. X}
  1115. X
  1116. X
  1117. X#ifndef __TURBOC__
  1118. local int cmptime(p, q)
  1119. struct tm *p, *q;       /* times to compare */
  1120. X/* Return negative if time p is before time q, positive if after, and
  1121. X   zero if the same */
  1122. X{
  1123. X  int r;                /* temporary variable */
  1124. X
  1125. X  if ((r = p->tm_year - q->tm_year) != 0)
  1126. X    return r;
  1127. X  else if ((r = p->tm_mon - q->tm_mon) != 0)
  1128. X    return r;
  1129. X  else if ((r = p->tm_mday - q->tm_mday) != 0)
  1130. X    return r;
  1131. X  else if ((r = p->tm_hour - q->tm_hour) != 0)
  1132. X    return r;
  1133. X  else if ((r = p->tm_min - q->tm_min) != 0)
  1134. X    return r;
  1135. X  else
  1136. X    return p->tm_sec - q->tm_sec;
  1137. X}
  1138. X
  1139. X
  1140. local time_t invlocal(t)
  1141. struct tm *t;           /* time to convert */
  1142. X/* Find inverse of localtime() using bisection.  This routine assumes that
  1143. X   time_t is an integer type, either signed or unsigned.  The expectation
  1144. X   is that sometime before the year 2038, time_t will be made a 64-bit
  1145. X   integer, and this routine will still work. */
  1146. X{
  1147. X  time_t i;             /* midpoint of current root range */
  1148. X  time_t l;             /* lower end of root range */
  1149. X  time_t u;             /* upper end of root range */
  1150. X
  1151. X  /* Bracket the root [0,largest time_t].  Note: if time_t is a 32-bit signed
  1152. X     integer, then the upper bound is GMT 1/19/2038 03:14:07, after which all
  1153. X     the Unix systems in the world come to a grinding halt.  Either that, or
  1154. X     all those systems will suddenly find themselves transported to December
  1155. X     of 1901 ... */
  1156. X  l = 0;
  1157. X  u = 1;
  1158. X  while (u < (u << 1))
  1159. X    u = (u << 1) + 1;
  1160. X
  1161. X  /* Find the root */
  1162. X  while (u - l > 1)
  1163. X  {
  1164. X    i = l + ((u - l) >> 1);
  1165. X    if (cmptime(localtime(&i), t) <= 0)
  1166. X      l = i;
  1167. X    else
  1168. X      u = i;
  1169. X  }
  1170. X  return l;
  1171. X}
  1172. X#endif /* !__TURBOC__ */
  1173. X
  1174. X
  1175. void stamp(f, d)
  1176. char *f;                /* name of file to change */
  1177. ulg d;                  /* dos-style time to change it to */
  1178. X/* Set last updated and accessed time of file f to the DOS time d. */
  1179. X{
  1180. X#ifdef __TURBOC__
  1181. X  int h;                /* file handle */
  1182. X
  1183. X  if ((h = open(f, 0)) != -1)
  1184. X  {
  1185. X    setftime(h, (struct ftime *)&d);
  1186. X    close(h);
  1187. X  }
  1188. X#else /* !__TURBOC__ */
  1189. X#ifdef VMS
  1190. X  warn("timestamp not implemented yet under VMS", "");
  1191. X#else /* !VMS */
  1192. X  struct tm t;          /* argument for invlocal() */
  1193. X  time_t u[2];          /* argument for utime() */
  1194. X
  1195. X  /* Convert DOS time to time_t format in u[0] and u[1] */
  1196. X  t.tm_sec = (int)(d << 1) & 0x3e;
  1197. X  t.tm_min = (int)(d >> 5) & 0x3f;
  1198. X  t.tm_hour = (int)(d >> 11) & 0x1f;
  1199. X  t.tm_mday = (int)(d >> 16) & 0x1f;
  1200. X  t.tm_mon = ((int)(d >> 21) & 0xf) - 1;
  1201. X  t.tm_year = ((int)(d >> 25) & 0x7f) + 80;
  1202. X  u[0] = u[1] = invlocal(&t);
  1203. X
  1204. X  /* Set updated and accessed times of f */
  1205. X  utime(f, u);
  1206. X#endif /* ?VMS */
  1207. X#endif /* ?__TURBOC__ */
  1208. X}
  1209. X
  1210. X
  1211. local void inctime(s)
  1212. struct tm *s;           /* time to increment in place */
  1213. X/* Increment the time structure *s by one second, return the result in
  1214. X   place. */
  1215. X{
  1216. X  int y;                /* temporary variable */
  1217. X
  1218. X  /* days in each month, except for February */
  1219. X  static int days[] = {31,0,31,30,31,30,31,31,30,31,30,31};
  1220. X
  1221. X  /* Set days in February from year (1900 is a leap year, 2000 is not) */
  1222. X  y = s->tm_year + 1900;
  1223. X  days[1] = y % 4 == 0 && (y % 100 != 0 || y % 400 == 0) ? 29 : 28;
  1224. X
  1225. X  /* Increment time with carry */
  1226. X  if (s->tm_sec != 59)
  1227. X    s->tm_sec++;
  1228. X  else if (s->tm_sec = 0, s->tm_min != 59)
  1229. X    s->tm_min++;
  1230. X  else if (s->tm_min = 0, s->tm_hour != 23)
  1231. X    s->tm_hour++;
  1232. X  else if (s->tm_hour = 0, s->tm_mday != days[s->tm_mon])
  1233. X    s->tm_mday++;
  1234. X  else if (s->tm_mday = 1, s->tm_mon != 11)
  1235. X    s->tm_mon++;
  1236. X  else
  1237. X  {
  1238. X    s->tm_mon = 0;
  1239. X    s->tm_year++;
  1240. X  }
  1241. X}
  1242. X
  1243. X
  1244. ulg dostime(y, n, d, h, m, s)
  1245. int y;                  /* year */
  1246. int n;                  /* month */
  1247. int d;                  /* day */
  1248. int h;                  /* hour */
  1249. int m;                  /* minute */
  1250. int s;                  /* second */
  1251. X/* Convert the date y/n/d and time h:m:s to a four byte DOS date and
  1252. X   time (date in high two bytes, time in low two bytes allowing magnitude
  1253. X   comparison). */
  1254. X{
  1255. X  return y < 1980 ? dostime(1980, 1, 1, 0, 0, 0) :
  1256. X        (((ulg)y - 1980) << 25) | ((ulg)n << 21) | ((ulg)d << 16) |
  1257. X        ((ulg)h << 11) | ((ulg)m << 5) | ((ulg)s >> 1);
  1258. X}
  1259. X
  1260. X
  1261. local ulg unix2dostime(t)
  1262. time_t *t;              /* unix time to convert */
  1263. X/* Return the Unix time t in DOS format, rounded up to the next two
  1264. X   second boundary. */
  1265. X{
  1266. X  struct tm *s;         /* result of localtime() */
  1267. X
  1268. X  s = localtime(t);             /* Use local time since MSDOS does */
  1269. X  inctime(s);                   /* Add one second to round up */
  1270. X  return dostime(s->tm_year + 1900, s->tm_mon + 1, s->tm_mday,
  1271. X                 s->tm_hour, s->tm_min, s->tm_sec);
  1272. X}
  1273. X
  1274. X
  1275. ulg filetime(f, a, n)
  1276. char *f;                /* name of file to get info on */
  1277. ulg *a;                 /* return value: file attributes */
  1278. long *n;                /* return value: file size */
  1279. X/* If file *f does not exist, return 0.  Else, return the file's last
  1280. X   modified date and time as an MSDOS date and time.  The date and
  1281. X   time is returned in a long with the date most significant to allow
  1282. X   unsigned integer comparison of absolute times.  Also, if a is not
  1283. X   a NULL pointer, store the file attributes there, with the high two
  1284. X   bytes being the Unix attributes, and the low byte being a mapping
  1285. X   of that to DOS attributes.  If n is not NULL, store the file size
  1286. X   there. */
  1287. X{
  1288. X  struct stat s;        /* results of stat() */
  1289. X
  1290. X#ifdef S_IFLNK
  1291. X  if (linkput ? lstat(f, &s) == 0 && ((s.st_mode & S_IFMT) == S_IFREG ||
  1292. X                                      (s.st_mode & S_IFMT) == S_IFLNK) :
  1293. X#else /* !S_IFLNK */
  1294. X  if (
  1295. X#endif /* ?S_IFLNK */
  1296. X                stat(f, &s) == 0 && (s.st_mode & S_IFMT) == S_IFREG)
  1297. X  {
  1298. X    if (a != NULL)
  1299. X      *a = (s.st_mode << 16) | !(s.st_mode & S_IWRITE);
  1300. X    if (n != NULL)
  1301. X      *n = s.st_size;
  1302. X#ifdef VMS
  1303. X    return unix2dostime(&s.st_ctime);   /* Use creation time in VMS */
  1304. X#else /* !VMS */
  1305. X    return unix2dostime(&s.st_mtime);
  1306. X#endif /* ?VMS */
  1307. X  }
  1308. X  else
  1309. X    return 0;
  1310. X}
  1311. X
  1312. X
  1313. int issymlnk(a)
  1314. ulg a;                  /* Attributes returned by filetime() */
  1315. X/* Return true if the attributes are those of a symbolic link */
  1316. X{
  1317. X#ifdef S_IFLNK
  1318. X  return ((a >> 16) & S_IFMT) == S_IFLNK;
  1319. X#else /* !S_IFLNK */
  1320. X  return (int)a & 0;    /* avoid warning on unused parameter */
  1321. X#endif /* ?S_IFLNK */
  1322. X}
  1323. X
  1324. X
  1325. int deletedir(d)
  1326. char *d;                /* directory to delete */
  1327. X/* Delete the (empty) directory *d.  Return the result of rmdir(), delete(),
  1328. X   or system(). */
  1329. X{
  1330. X#ifdef RMDIR
  1331. X  /* code from Greg Roelofs, who horked it from Mark Edwards (unzip) */
  1332. X  int r, len;
  1333. X  char *s;              /* malloc'd string for system command */
  1334. X
  1335. X  len = strlen(d);
  1336. X  if ((s = malloc(len + 34)) == NULL)
  1337. X    return 127;
  1338. X
  1339. X#ifdef VMS
  1340. X  {
  1341. X    char *c;            /* pointer into VMS path */
  1342. X    /* convert "DEV:[DIR.SUB1.SUB2]" form to "DEV:[DIR.SUB1]SUB2.DIR;0" */
  1343. X    strcat(strcpy(s, "set prot=(o:rwed) "), d);   /* d starts at s+18 */
  1344. X    if (*(c = s+17+len) != ']')
  1345. X    {
  1346. X      free(s);
  1347. X      return 127;
  1348. X    }
  1349. X    strcpy(c, ".DIR;0");        /* 0 translates to highest version */
  1350. X    while (--c > s+18  &&  *c != '.'  &&  *c != '[') ;
  1351. X    if (c == s+18)
  1352. X    {
  1353. X      free(s);
  1354. X      return 127;
  1355. X    }
  1356. X    if (*c == '.')
  1357. X      *c = ']';
  1358. X    else if (*--c == ']')  /* presumably of form "DEV:[DIR.SUB1.][SUB2]" */
  1359. X    {                      /* (possible to have "DEV:[DIR.SUB1.][][SUB2]"?) */
  1360. X      char *b = c + 2;
  1361. X      c[-1] = ']';
  1362. X      while (*c++ = *b++) ;
  1363. X    }
  1364. X    else        /* must have reached device name:  can't delete top level */
  1365. X    {
  1366. X      free(s);
  1367. X      return 127;
  1368. X    }
  1369. X  }
  1370. X  /* unprotect directory and delete it as a file.  May fail if exists 
  1371. X     normal file "foo.dir" on top of directory "foo.dir" */
  1372. X  system(s);
  1373. X  r = delete(s+18);
  1374. X#else /* !VMS */
  1375. X  sprintf(s, "IFS=\" \t\n\" /bin/rmdir %s 2>/dev/null", d);
  1376. X  r = system(s);
  1377. X#endif /* ?VMS */
  1378. X  free(s);
  1379. X  return r;
  1380. X#else /* !RMDIR */
  1381. X  return rmdir(d);
  1382. X#endif /* ?RMDIR */
  1383. X}
  1384. X
  1385. X
  1386. X#endif /* !UTIL */
  1387. X
  1388. X
  1389. int destroy(f)
  1390. char *f;                /* file to delete */
  1391. X/* Delete the file *f, returning non-zero on failure. */
  1392. X{
  1393. X  return unlink(f);
  1394. X}
  1395. X
  1396. X
  1397. int replace(d, s)
  1398. char *d, *s;            /* destination and source file names */
  1399. X/* Replace file *d by file *s, removing the old *s.  Return an error code
  1400. X   in the ZE_ class. */
  1401. X{
  1402. X  struct stat t;        /* results of stat() */
  1403. X
  1404. X  if (stat(d, &t) == 0 && unlink(d))
  1405. X    return ZE_CREAT;                    /* Can't erase zip file--give up */
  1406. X  if (link(s, d))                       /* Just move s on top of d */
  1407. X#ifndef VMS                             /* For VMS, assume failure is EXDEV */
  1408. X    if (errno != EXDEV)
  1409. X      return ZE_CREAT;
  1410. X    else
  1411. X#endif /* !VMS */
  1412. X    {
  1413. X      FILE *f, *g;      /* source and destination files */
  1414. X      int r;            /* temporary variable */
  1415. X
  1416. X      if ((f = fopen(s, FOPR)) == NULL)
  1417. X        return ZE_TEMP;
  1418. X      if ((g = fopen(d, FOPW)) == NULL)
  1419. X      {
  1420. X        fclose(f);
  1421. X        return ZE_CREAT;
  1422. X      }
  1423. X      r = fcopy(f, g, (ulg)-1L);
  1424. X      fclose(f);
  1425. X      if (fclose(g) || r != ZE_OK)
  1426. X      {
  1427. X        unlink(d);
  1428. X        return r ? (r == ZE_TEMP ? ZE_WRITE : r) : ZE_WRITE;
  1429. X      }
  1430. X#ifdef VMS /* only delete if rename failed:  previous version may exist */
  1431. X      unlink(s);
  1432. X    }
  1433. X#else /* !VMS */
  1434. X    }
  1435. X  unlink(s);
  1436. X#endif /* !VMS */
  1437. X  return ZE_OK;
  1438. X}
  1439. X
  1440. X
  1441. int getfileattr(f)
  1442. char *f;                /* file path */
  1443. X/* Return the file attributes for file f or -1 if failure */
  1444. X{
  1445. X  struct stat s;
  1446. X
  1447. X  return stat(f, &s) == 0 ? s.st_mode : 0;
  1448. X}
  1449. X
  1450. X
  1451. int setfileattr(f, a)
  1452. char *f;                /* file path */
  1453. int a;                  /* attributes returned by getfileattr() */
  1454. X/* Give the file f the attributes a, return non-zero on failure */
  1455. X{
  1456. X#ifdef VMS
  1457. X  return 0;
  1458. X#else /* !VMS */
  1459. X  return chmod(f, a);
  1460. X#endif /* ?VMS */
  1461. X}
  1462. X
  1463. X
  1464. char *tempname(c)
  1465. int c;                  /* character to insert in name */
  1466. X/* Return a temporary file name in its own malloc'ed space, using tempath. */
  1467. X{
  1468. X  char *p;              /* temporary pointer */
  1469. X  char *t;              /* malloc'ed space for name */
  1470. X  
  1471. X  if (tempath != NULL)
  1472. X  {
  1473. X    if ((t = malloc(strlen(tempath)+10)) == NULL)
  1474. X      return NULL;
  1475. X    strcpy(t, tempath);
  1476. X    if (t[strlen(t)-1] != '/')
  1477. X      strcat(t, "/");
  1478. X  }
  1479. X  else
  1480. X  {
  1481. X    if ((t = malloc(9)) == NULL)
  1482. X      return NULL;
  1483. X    *t = 0;
  1484. X  }
  1485. X  p = t + strlen(t);
  1486. X  *p++ = '_';
  1487. X  *p++ = (char)c;
  1488. X  strcpy(p, "XXXXXX");
  1489. X  return mktemp(t);
  1490. X}
  1491. X
  1492. X
  1493. int fcopy(f, g, n)
  1494. XFILE *f, *g;            /* source and destination files */
  1495. ulg n;                  /* number of bytes to copy or -1 for all */
  1496. X/* Copy n bytes from file *f to file *g, or until EOF if n == -1.  Return
  1497. X   an error code in the ZE_ class. */
  1498. X{
  1499. X  char *b;              /* malloc'ed buffer for copying */
  1500. X  extent k;             /* result of fread() */
  1501. X  ulg m;                /* bytes copied so far */
  1502. X
  1503. X  if ((b = malloc(BSZ)) == NULL)
  1504. X    return ZE_MEM;
  1505. X  m = 0;
  1506. X  while (n == -1L || m < n)
  1507. X  {
  1508. X    if ((k = fread(b, 1, n == -1 ?
  1509. X                   BSZ : (n - m < BSZ ? (extent)(n - m) : BSZ), f)) == 0)
  1510. X      if (ferror(f))
  1511. X      {
  1512. X        free((voidp *)b);
  1513. X        return ZE_READ;
  1514. X      }
  1515. X      else
  1516. X        break;
  1517. X    if (fwrite(b, 1, k, g) != k)
  1518. X    {
  1519. X      free((voidp *)b);
  1520. X      return ZE_TEMP;
  1521. X    }
  1522. X    m += k;
  1523. X  }
  1524. X  free((voidp *)b);
  1525. X  return ZE_OK;
  1526. X}
  1527. X
  1528. X
  1529. X#ifndef EXPORT
  1530. X
  1531. X#ifndef MSVMS
  1532. X
  1533. local int echofd = -1;  /* file descriptor whose echo is off */
  1534. X
  1535. void echoff(f)
  1536. int f;                  /* file descriptor to turn echo off on */
  1537. X/* Turn echo off for file descriptor f.  Assumes that f is a tty device. */
  1538. X{
  1539. X  struct sgttyb sg;     /* tty device structure */
  1540. X
  1541. X  echofd = f;
  1542. X  GTTY(f, &sg);                                 /* get settings */
  1543. X  sg.sg_flags &= ~ECHO;                         /* turn echo off */
  1544. X  STTY(f, &sg);
  1545. X}
  1546. X
  1547. void echon()
  1548. X/* Turn echo back on for file descriptor echofd. */
  1549. X{
  1550. X  struct sgttyb sg;     /* tty device structure */
  1551. X
  1552. X  if (echofd != -1)
  1553. X  {
  1554. X    GTTY(echofd, &sg);                          /* get settings */
  1555. X    sg.sg_flags |= ECHO;                        /* turn echo on */
  1556. X    STTY(echofd, &sg);
  1557. X    echofd = -1;
  1558. X  }
  1559. X}
  1560. X
  1561. X#endif /* !MSVMS */
  1562. X
  1563. X
  1564. char *getp(m, p, n)
  1565. char *m;                /* prompt for password */
  1566. char *p;                /* return value: line input */
  1567. int n;                  /* bytes available in p[] */
  1568. X/* Get a password of length n-1 or less into *p using the prompt *m.
  1569. X   The entered password is not echoed.  Return p on success, NULL on
  1570. X   failure (can't get controlling tty). */
  1571. X{
  1572. X  char c;               /* one-byte buffer for read() to use */
  1573. X  int i;                /* number of characters input */
  1574. X  char *w;              /* warning on retry */
  1575. X
  1576. X#ifndef MSVMS
  1577. X  int f;                /* file decsriptor for tty device */
  1578. X
  1579. X  /* Turn off echo on tty */
  1580. X  if (!isatty(2))
  1581. X    return NULL;                                /* error if not tty */
  1582. X  if ((f = open(ttyname(2), 0, 0)) == -1)
  1583. X    return NULL;
  1584. X  echoff(f);                                    /* turn echo off */
  1585. X#endif /* !MSVMS */
  1586. X
  1587. X  /* Get password */
  1588. X  w = "";
  1589. X  do {
  1590. X    fputs(w, stderr);                           /* warning if back again */
  1591. X    fputs(m, stderr);                           /* prompt */
  1592. X    fflush(stderr);
  1593. X    i = 0;
  1594. X    do {                                        /* read line, keeping n */
  1595. X#ifdef MSVMS
  1596. X      if ((c = (char)getch()) == '\r')
  1597. X        c = '\n';
  1598. X#else /* !MSVMS */
  1599. X      read(f, &c, 1);
  1600. X#endif /* ?MSVMS */
  1601. X      if (i < n)
  1602. X        p[i++] = c;
  1603. X    } while (c != '\n');
  1604. X    putc('\n', stderr);  fflush(stderr);
  1605. X    w = "(line too long--try again)\n";
  1606. X  } while (p[i-1] != '\n');
  1607. X  p[i-1] = 0;                                   /* terminate at newline */
  1608. X
  1609. X#ifndef MSVMS
  1610. X  /* Turn echo back on */
  1611. X  echon();                                      /* turn echo back on */
  1612. X  close(f);
  1613. X#endif /* !MSVMS */
  1614. X
  1615. X  /* Return pointer to password */
  1616. X  return p;
  1617. X}
  1618. X
  1619. X#endif /* !EXPORT */
  1620. X
  1621. X
  1622. X#ifdef ZMEM
  1623. X
  1624. X/************************/
  1625. X/*  Function memset()  */
  1626. X/************************/
  1627. X
  1628. X/*
  1629. X * memset - for systems without it
  1630. X *  bill davidsen - March 1990
  1631. X */
  1632. X
  1633. char *
  1634. memset(buf, init, len)
  1635. register char *buf;     /* buffer loc */
  1636. register int init;      /* initializer */
  1637. register unsigned int len;   /* length of the buffer */
  1638. X{
  1639. X    char *start;
  1640. X
  1641. X    start = buf;
  1642. X    while (len--) *(buf++) = init;
  1643. X    return(start);
  1644. X}
  1645. X
  1646. X
  1647. X/************************/
  1648. X/*  Function memcpy()  */
  1649. X/************************/
  1650. X
  1651. char *
  1652. memcpy(dst,src,len)           /* v2.0f */
  1653. register char *dst, *src;
  1654. register unsigned int len;
  1655. X{
  1656. X    char *start;
  1657. X
  1658. X    start = dst;
  1659. X    while (len--)
  1660. X        *dst++ = *src++;
  1661. X    return(start);
  1662. X}
  1663. X
  1664. X
  1665. X/************************/
  1666. X/*  Function memcmp()  */
  1667. X/************************/
  1668. X
  1669. int
  1670. memcmp(b1,b2,len)                     /* jpd@usl.edu -- 11/16/90 */
  1671. register char *b1, *b2;
  1672. register unsigned int len;
  1673. X{
  1674. X
  1675. X    if (len) do {             /* examine each byte (if any) */
  1676. X      if (*b1++ != *b2++)
  1677. X        return (*--((uch *)b1) - *--((uch *)b2));  /* exit when miscompare */
  1678. X       } while (--len);
  1679. X
  1680. X    return(0);        /* no miscompares, yield 0 result */
  1681. X}
  1682. X
  1683. X#endif  /* ZMEM */
  1684. END_OF_FILE
  1685. if test 44358 -ne `wc -c <'fileio.c'`; then
  1686.     echo shar: \"'fileio.c'\" unpacked with wrong size!
  1687. fi
  1688. # end of 'fileio.c'
  1689. fi
  1690. echo shar: End of archive 6 \(of 7\).
  1691. cp /dev/null ark6isdone
  1692. MISSING=""
  1693. for I in 1 2 3 4 5 6 7 ; do
  1694.     if test ! -f ark${I}isdone ; then
  1695.     MISSING="${MISSING} ${I}"
  1696.     fi
  1697. done
  1698. if test "${MISSING}" = "" ; then
  1699.     echo You have unpacked all 7 archives.
  1700.     rm -f ark[1-9]isdone
  1701. else
  1702.     echo You still need to unpack the following archives:
  1703.     echo "        " ${MISSING}
  1704. fi
  1705. ##  End of shell archive.
  1706. exit 0
  1707.